//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   ifdiv
//File Name     :   float_format.v
//Module name   :   float format
//Full name     :   float number format transfering 
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.0
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//1.01: add pipeline stall port
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//----------------------------- 
module gc_ifdiv(
    clk,
    rst_n,
    busy,
    en,
    type_a,
    type_b,
    a,
    b,
    type_q,
    valid,
    quotient,
    exception
);

input         clk;
input         rst_n;
input         busy;
input         en;
input  [1:0]  type_a;
input  [1:0]  type_b;
input  [31:0] a;
input  [31:0] b;
input  [1:0]  type_q;
output        valid;
output [31:0] quotient;
output [2:0]  exception;


//--------------------------------------------------------------
// stage 1
//--------------------------------------------------------------

reg [1:0]   type_q_ff1;
wire        sign_a;
wire [8:0]  exp_a;
wire [30:0] man_a;
wire        iszero_a;
wire        isinf_a;
wire        isnan_a;   
wire        sign_b;
wire [8:0]  exp_b;
wire [30:0] man_b;
wire        iszero_b;
wire        isinf_b;
wire        isnan_b;
wire        valid_format;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) type_q_ff1 <= 2'b0;
    else if(en && !busy) type_q_ff1 <= type_q;
end


float_format u_a_format(
    .clk   (clk),
    .rst_n (rst_n),
    .busy  (busy),
    .en    (en),
    .din   (a),
    .type_i(type_a),
    .sign  (sign_a),
    .exp   (exp_a),
    .man   (man_a),
    .iszero(iszero_a),
    .isinf (isinf_a),
    .isnan (isnan_a),
    .valid (valid_format)
);     

float_format u_b_format(
    .clk   (clk  ),
    .rst_n (rst_n),
    .busy  (busy),
    .en    (en   ),
    .din   (b),
    .type_i(type_b),
    .sign  (sign_b),
    .exp   (exp_b),
    .man   (man_b),
    .iszero(iszero_b),
    .isinf (isinf_b),
    .isnan (isnan_b),
    .valid ()
);            


//--------------------------------------------------------------
// stage 2
//--------------------------------------------------------------

reg [1:0]   type_q_ff2;
reg         sign_a_ff2;
reg [8:0]   exp_a_ff2;
reg [30:0]  man_a_ff2;
reg         iszero_a_ff2;
reg         isinf_a_ff2;
reg         isnan_a_ff2; 
wire        valid_rcp;
wire        sign_rcp;
wire[24:0]  man_ff;
wire[24:0]  man_rcp;
wire[8:0]   exp_rcp;
wire        iszero_rcp;
wire        isinf_rcp;
wire        isnan_rcp;     

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        type_q_ff2 <= 2'b0;
        sign_a_ff2   <= 0;
        exp_a_ff2    <= 0;
        man_a_ff2    <= 0;
        iszero_a_ff2 <= 0;
        isinf_a_ff2  <= 0;
        isnan_a_ff2  <= 0;
    end
    else if(valid_format && !busy)
    begin
        type_q_ff2 <= type_q_ff1;
        sign_a_ff2   <= sign_a  ;
        exp_a_ff2    <= exp_a   ;
        man_a_ff2    <= man_a   ;
        iszero_a_ff2 <= iszero_a;
        isinf_a_ff2  <= isinf_a ;
        isnan_a_ff2  <= isnan_a ;
    end
end


float_rcp u_float_rcp(
    .clk       (clk),
    .rst_n     (rst_n),
    .busy      (busy),
    .en        (valid_format),
    .sign      (sign_b),
    .exp       (exp_b),
    .man       (man_b),
    .iszero    (iszero_b),
    .isinf     (isinf_b),
    .isnan     (isnan_b),
    .sign_rcp  (sign_rcp  ),
    .man_ff    (man_ff    ),
    .man_rcp   (man_rcp   ),
    .exp_rcp   (exp_rcp   ),
    .iszero_rcp(iszero_rcp),
    .isinf_rcp (isinf_rcp ),
    .isnan_rcp (isnan_rcp ),
    .valid     (valid_rcp)
);   


//--------------------------------------------------------------
// stage 3-4
//--------------------------------------------------------------

reg [1:0]   type_q_ff3;
reg         sign_a_ff3;
reg [8:0]   exp_a_ff3;
reg [30:0]  man_a_ff3;
reg         iszero_a_ff3;
reg         isinf_a_ff3;
reg         isnan_a_ff3;   


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        type_q_ff3 <= 2'b0;
        sign_a_ff3   <= 0;
        exp_a_ff3    <= 0;
        man_a_ff3    <= 0;
        iszero_a_ff3 <= 0;
        isinf_a_ff3  <= 0;
        isnan_a_ff3  <= 0;
    end
    else if(valid_rcp && !busy)
    begin
        type_q_ff3 <= type_q_ff2;
        sign_a_ff3   <= sign_a_ff2  ;
        exp_a_ff3    <= exp_a_ff2   ;
        man_a_ff3    <= man_a_ff2   ;
        iszero_a_ff3 <= iszero_a_ff2;
        isinf_a_ff3  <= isinf_a_ff2 ;
        isnan_a_ff3  <= isnan_a_ff2 ;
    end
end      

reg         valid_rcp_ff1;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) valid_rcp_ff1 <= 1'b0;
    else if(!busy) valid_rcp_ff1 <= valid_rcp;
end

reg [1:0]   type_q_ff4;
reg         sign_a_ff4;
reg [8:0]   exp_a_ff4;
reg [30:0]  man_a_ff4;
reg         iszero_a_ff4;
reg         isinf_a_ff4;
reg         isnan_a_ff4;   

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        type_q_ff4 <= 2'b0;
        sign_a_ff4   <= 0;
        exp_a_ff4    <= 0;
        man_a_ff4    <= 0;
        iszero_a_ff4 <= 0;
        isinf_a_ff4  <= 0;
        isnan_a_ff4  <= 0;
    end
    else if(valid_rcp_ff1 && !busy)
    begin
        type_q_ff4 <= type_q_ff3;
        sign_a_ff4   <= sign_a_ff3  ;
        exp_a_ff4    <= exp_a_ff3   ;
        man_a_ff4    <= man_a_ff3   ;
        iszero_a_ff4 <= iszero_a_ff3;
        isinf_a_ff4  <= isinf_a_ff3 ;
        isnan_a_ff4  <= isnan_a_ff3 ;
    end
end                 

wire [8:0]   exp_newton;
wire [24:0]  man_newton;
wire         sign_newton;
wire         iszero_newton;
wire         isinf_newton;
wire         isnan_newton;   
wire         valid_newton;           

float_newton u_float_newton(
    .clk          (clk          ),
    .rst_n        (rst_n        ),
    .busy         (busy),
    .en           (valid_rcp    ),
    .exp_rcp      (exp_rcp      ),
    .man_rcp      (man_rcp      ),
    .man_ff       (man_ff       ),
    .sign_rcp     (sign_rcp     ),
    .iszero_rcp   (iszero_rcp   ),
    .isinf_rcp    (isinf_rcp    ),
    .isnan_rcp    (isnan_rcp    ),
    .exp_newton   (exp_newton   ),
    .man_newton   (man_newton   ),
    .sign_newton  (sign_newton  ),
    .iszero_newton(iszero_newton),
    .isinf_newton (isinf_newton ),
    .isnan_newton (isnan_newton ),  
    .valid        (valid_newton )
); 

//--------------------------------------------------------------
// stage 5
//--------------------------------------------------------------   
wire [8:0]  exp_mult;
wire        sign_mult;
wire [30:0] man_mult;
wire [2:0]  exception_mult;
wire        iszero_mult;
wire        valid_mult;     

reg [1:0]   type_q_ff5;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        type_q_ff5 <= 2'b0;
    end
    else if(valid_newton && !busy)
    begin
        type_q_ff5 <= type_q_ff4;
    end
end       

float_mult u_float_mult(
    .clk           (clk           ),
    .rst_n         (rst_n         ),
    .busy          (busy),
    .en            (valid_newton  ),
    .exp_a         (exp_a_ff4     ),
    .man_a         (man_a_ff4     ),
    .sign_a        (sign_a_ff4    ),
    .iszero_a      (iszero_a_ff4  ),
    .isinf_a       (isinf_a_ff4   ),
    .isnan_a       (isnan_a_ff4   ),
    .exp_newton    (exp_newton    ),
    .man_newton    (man_newton    ),
    .sign_newton   (sign_newton   ),
    .iszero_newton (iszero_newton ),
    .isinf_newton  (isinf_newton  ),
    .isnan_newton  (isnan_newton  ),
    .exp_mult      (exp_mult      ),
    .sign_mult     (sign_mult     ),
    .man_mult      (man_mult      ),
    .iszero_mult   (iszero_mult   ),
    .exception_mult(exception_mult),
    .valid         (valid_mult    )
);  

//--------------------------------------------------------------
// stage 6
//-------------------------------------------------------------- 
reg [1:0]   type_q_ff6;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        type_q_ff6 <= 2'b0;
    end
    else if(valid_mult && !busy)
    begin
        type_q_ff6 <= type_q_ff5;
    end
end       

float_output u_float_output(
    .clk           (clk           ),
    .rst_n         (rst_n         ),
    .busy          (busy),
    .en            (valid_mult    ),
    .exp_mult      (exp_mult      ),
    .sign_mult     (sign_mult     ),
    .man_mult      (man_mult      ),
    .exception_mult(exception_mult),
    .iszero_mult   (iszero_mult   ),
    .type_q        (type_q_ff5    ),
    .quetient      (quotient      ),
    .exception     (exception     ),
    .valid         (valid         )
);







endmodule
